/*******************************************************************************
 * Copyright (c) 2011, 2012 Link Management & Technology S.p.A. 
 * via R. Scotellaro, 55 - 73100 - Lecce - http://www.linksmt.it
 * All rights reserved. 
 *
 * Contributors:
 *     Links Management & Technology S.p.A. - initial API and implementation
 *******************************************************************************/
package it.linksmt.tooling.jpaddlplugin;

import it.linksmt.tooling.jpaddlplugin.impl.DDLClassLoader;
import it.linksmt.tooling.jpaddlplugin.impl.DDLGeneratorTool;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.logging.SessionLog;

/**
 * Generate DDL schema files (drop and create statements) from a JPA persistence file.
 * 
 * See eclipselink (http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29) for information about
 * the Eclipselink parameters.
 * 
 * See http://maven.apache.org/guides/mini/guide-maven-classloading.html for classloading in maven.
 * 
 * @phase process-classes
 * @goal generate-schema
 * @requiresOnline false
 * @requiresDependencyResolution
 */
public class JpaDdlMojo extends AbstractMojo {
	/**
	 * Qualified package name for the platform database classes used by EclipseLink (e.g., MySQLPlatform).
	 */
	private static final String ECLIPSELINK_PLATFORM_PACKAGE = "org.eclipse.persistence.platform.database";

	/**
	 * JPA Persistence Unit (PU) name.
	 * 
	 * @parameter 
	 * 	 expression="${generateDdl.persistenceUnitName}"
	 * @required
	 */
	private String persistenceUnitName = "";

	/**
	 * JPA Persistence Unit(s) file name.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.persistenceUnitFile}"
	 * 		default-value="${project.build.sourceDirectory}/main/resources/META-INF/persistence.xml"
	 * @required
	 */
	private String persistenceUnitFile = "META-INF/ddl-persistence.xml";

	/**
	 * Output directory for generated DDL files.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.outputDirectory}"
	 * 		default-value="${project.build.directory}/generated-sources/sql"
	 * @required
	 */
	private String ddlOutputDir = "";
	
	/**
	 * File name for the output directory name. By default, &lt;puName&gt;-ddl-create.sql.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.ddlCreateFileName}"
	 * 		default-value="database-ddl-create.sql"
	 * @required
	 */
	private String ddlCreateFileName;

	/**
	 * File name for the output directory name. By default, database-ddl-create.sql.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.ddlDropFileName}"
	 * 		default-value="database-ddl-drop.sql"
	 * @required
	 */
	private String ddlDropFileName;

	/**
	 * Generation mode for the schema files: add create tables statements ("create-tables"), add drop and 
	 * create statements ("drop-and-create-tables") or do nothing ("none"). By default, 
	 * "drop-and-create-tables" is used.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.ddlGenerationMode}"
	 * 		default-value="drop-and-create-tables"
	 * @required
	 */
	private String ddlGenerationMode = PersistenceUnitProperties.DROP_AND_CREATE;

	/**
	 * Logging level for the generation operation. By default, "INFO" is selected.
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.ddlGenerationLoggingLevel}"
	 * 		default-value="INFO"
	 * @required
	 */
	private String ddlGenerationLoggingLevel = SessionLog.FINEST_LABEL; //SessionLog.INFO_LABEL;

	/**
	 * The DBMS target platform to use when generating SQL statements. This must be the name of the platform class, without
	 * the package "org.eclipse.persistence.platform.database" (e.g, "MySQLPlatform" is used to target the
	 * "org.eclipse.persistence.platform.database.MySQLPlatform" class).
	 * 
	 * @parameter 
	 * 		expression="${generateDdl.targetDbPlatform}"
	 * @required
	 */
	private String targetDbPlatform = "";

	/**
	 * The project currently being built.
	 * 
	 * @parameter expression="${project}"
	 * @required
	 * @readonly
	 */
	private MavenProject project;
	
	/* (non-Javadoc)
	 * @see org.apache.maven.plugin.Mojo#execute()
	 */
	@Override
	public void execute() throws MojoExecutionException {
		Log logger = getLog();

		try {
			DDLParameters params = makeParams();
			DDLClassLoader classLoader = DDLClassLoader.create( this.getClass().getClassLoader(), project, params );

			DDLGeneratorTool tooling = new DDLGeneratorTool( params, classLoader, logger );
			tooling.generateSchema();
		} catch (Throwable e) {
			throw new MojoExecutionException( "Error while generating schema", e );
		} 
	}
	
	/**
	 * Assemble the parameters for this plugin.
	 * 
	 * @return the plugin parameters.
	 */
	private DDLParameters makeParams() {
		DDLParameters parameters = new DDLParameters();
		
		parameters.setPersistenceUnitName( persistenceUnitName );
		parameters.setPersistenceUnitFile( persistenceUnitFile );
		parameters.setDdlOutputDir( ddlOutputDir );

		if (isEmptyParameter( ddlCreateFileName )) {
			ddlCreateFileName = String.format( "%s-ddl-create.sql", persistenceUnitName );
		}
		parameters.setDdlCreateFileName( ddlCreateFileName );
		
		if (isEmptyParameter( ddlDropFileName )) {
			ddlDropFileName = String.format( "%s-ddl-drop.sql", persistenceUnitName );
		}
		parameters.setDdlDropFileName( ddlDropFileName );
		
		parameters.setDdlGenerationMode( ddlGenerationMode );
		parameters.setDdlGenerationLoggingLevel( ddlGenerationLoggingLevel );
		parameters.setTargetDbPlatform( ECLIPSELINK_PLATFORM_PACKAGE + "." + targetDbPlatform );
		
		return parameters;
	}
	
	/**
	 * Check if string is null or empty (trims space chars).
	 * @param s the string to check
	 * @return <code>true</code> if string is <code>null</code> or empty, <code>false</code> otherwise.
	 */
	private static boolean isEmptyParameter( String s ) {
		return s == null || s.trim().length() == 0;
	}
}
